import { afterEach, expect, vi } from 'vitest'
import { cleanup } from '@testing-library/react'
import * as matchers from '@testing-library/jest-dom/matchers'

// 扩展expect断言
expect.extend(matchers)

// 每次测试后清理
afterEach(() => {
  cleanup()
  vi.clearAllMocks()
})

// Mock IntersectionObserver
global.IntersectionObserver = class IntersectionObserver {
  constructor() {}
  disconnect() {}
  observe() {}
  unobserve() {}
}

// Mock ResizeObserver
global.ResizeObserver = class ResizeObserver {
  constructor() {}
  disconnect() {}
  observe() {}
  unobserve() {}
}

// Mock matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: (query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: () => {},
    removeListener: () => {},
    addEventListener: () => {},
    removeEventListener: () => {},
    dispatchEvent: () => {},
  }),
})

// Mock window.scrollTo
Object.defineProperty(window, 'scrollTo', {
  writable: true,
  value: vi.fn(),
})

// Mock window.getComputedStyle
Object.defineProperty(window, 'getComputedStyle', {
  writable: true,
  value: () => ({
    getPropertyValue: () => '',
  }),
})

// Mock HTMLElement.prototype.scrollIntoView
HTMLElement.prototype.scrollIntoView = vi.fn()

// Mock console methods to reduce noise in tests
global.console = {
  ...console,
  // 保留错误和警告，但静音其他日志
  log: vi.fn(),
  debug: vi.fn(),
  info: vi.fn(),
  warn: console.warn,
  error: console.error,
}

// Mock Framer Motion
vi.mock('framer-motion', () => ({
  motion: {
    div: 'div',
    span: 'span',
    h1: 'h1',
    h2: 'h2',
    h3: 'h3',
    p: 'p',
    button: 'button',
    img: 'img',
    section: 'section',
    article: 'article',
    nav: 'nav',
    ul: 'ul',
    li: 'li',
    a: 'a',
    input: 'input',
    textarea: 'textarea',
    select: 'select',
    option: 'option',
    form: 'form',
    label: 'label',
    fieldset: 'fieldset',
    legend: 'legend',
    table: 'table',
    thead: 'thead',
    tbody: 'tbody',
    tr: 'tr',
    td: 'td',
    th: 'th',
    header: 'header',
    footer: 'footer',
    main: 'main',
    aside: 'aside',
    canvas: 'canvas',
    svg: 'svg',
    path: 'path',
    circle: 'circle',
    rect: 'rect',
    line: 'line',
    polygon: 'polygon',
    polyline: 'polyline',
    ellipse: 'ellipse',
    g: 'g',
    defs: 'defs',
    clipPath: 'clipPath',
    mask: 'mask',
    pattern: 'pattern',
    linearGradient: 'linearGradient',
    radialGradient: 'radialGradient',
    stop: 'stop',
    text: 'text',
    tspan: 'tspan',
    textPath: 'textPath',
    image: 'image',
    use: 'use',
    symbol: 'symbol',
    marker: 'marker',
    foreignObject: 'foreignObject',
    switch: 'switch',
    style: 'style',
    script: 'script',
    title: 'title',
    desc: 'desc',
    metadata: 'metadata',
  },
  AnimatePresence: ({ children }) => children,
  useAnimation: () => ({
    start: vi.fn(),
    stop: vi.fn(),
    set: vi.fn(),
  }),
  useInView: () => false,
  useMotionValue: (initial) => ({
    get: () => initial,
    set: vi.fn(),
    onChange: vi.fn(),
  }),
  useTransform: (value, inputRange, outputRange) => value,
  useSpring: (value) => value,
  useScroll: () => ({
    scrollX: { get: () => 0 },
    scrollY: { get: () => 0 },
    scrollXProgress: { get: () => 0 },
    scrollYProgress: { get: () => 0 },
  }),
  useViewportScroll: () => ({
    scrollX: { get: () => 0 },
    scrollY: { get: () => 0 },
    scrollXProgress: { get: () => 0 },
    scrollYProgress: { get: () => 0 },
  }),
  useDragControls: () => ({
    start: vi.fn(),
    stop: vi.fn(),
  }),
  useAnimationControls: () => ({
    start: vi.fn(),
    stop: vi.fn(),
    set: vi.fn(),
  }),
  usePresence: () => [true, vi.fn()],
  useReducedMotion: () => false,
  useIsomorphicLayoutEffect: vi.fn(),
  useCycle: (initial) => [initial, vi.fn()],
  useMotionValueEvent: vi.fn(),
  useMotionTemplate: (template) => template,
  useElementSize: () => ({ width: 0, height: 0 }),
  useViewportSize: () => ({ width: 0, height: 0 }),
  useMotionValue: (initial) => ({
    get: () => initial,
    set: vi.fn(),
    onChange: vi.fn(),
  }),
}))

// Mock Three.js
vi.mock('three', () => ({
  Scene: vi.fn(),
  PerspectiveCamera: vi.fn(),
  WebGLRenderer: vi.fn(),
  BoxGeometry: vi.fn(),
  MeshBasicMaterial: vi.fn(),
  Mesh: vi.fn(),
  AmbientLight: vi.fn(),
  DirectionalLight: vi.fn(),
  Color: vi.fn(),
  Vector3: vi.fn(),
  Euler: vi.fn(),
  MathUtils: {
    degToRad: vi.fn(),
    radToDeg: vi.fn(),
  },
}))

// Mock @react-three/fiber
vi.mock('@react-three/fiber', () => ({
  Canvas: ({ children }) => children,
  useFrame: vi.fn(),
  useThree: () => ({
    camera: {},
    scene: {},
    gl: {},
    size: { width: 800, height: 600 },
    viewport: { width: 800, height: 600 },
  }),
  extend: vi.fn(),
  useLoader: vi.fn(),
  useTexture: vi.fn(),
}))

// Mock @react-three/drei
vi.mock('@react-three/drei', () => ({
  OrbitControls: () => null,
  Text: () => null,
  Box: () => null,
  Sphere: () => null,
  Plane: () => null,
  useGLTF: vi.fn(),
  useFBX: vi.fn(),
  useTexture: vi.fn(),
  useProgress: () => ({ progress: 100, active: false, errors: [], item: '', loaded: 100, total: 100 }),
  Html: ({ children }) => children,
  ContactShadows: () => null,
  Environment: () => null,
  Sky: () => null,
  Stars: () => null,
  Cloud: () => null,
  Float: ({ children }) => children,
  MeshWobbleMaterial: () => null,
  MeshDistortMaterial: () => null,
  MeshReflectorMaterial: () => null,
  MeshRefractionMaterial: () => null,
  MeshTransmissionMaterial: () => null,
  MeshDiscardMaterial: () => null,
  MeshBasicMaterial: () => null,
  MeshStandardMaterial: () => null,
  MeshPhysicalMaterial: () => null,
  MeshLambertMaterial: () => null,
  MeshPhongMaterial: () => null,
  MeshToonMaterial: () => null,
  MeshNormalMaterial: () => null,
  MeshDepthMaterial: () => null,
  MeshDistanceMaterial: () => null,
  MeshMatcapMaterial: () => null,
  MeshLineMaterial: () => null,
  LineBasicMaterial: () => null,
  LineDashedMaterial: () => null,
  PointsMaterial: () => null,
  SpriteMaterial: () => null,
  RawShaderMaterial: () => null,
  ShaderMaterial: () => null,
  ShadowMaterial: () => null,
}))

// 全局测试工具函数
import { render } from '@testing-library/react'
import { BrowserRouter } from 'react-router-dom'

global.renderWithRouter = (ui, options) => {
  return render(ui, { 
    wrapper: BrowserRouter,
    ...options 
  })
}

// 自定义测试工具函数
global.createMockUser = () => ({
  id: '1',
  name: '测试用户',
  email: 'test@example.com',
  avatar: '👤',
  verified: true,
})

global.createMockPost = () => ({
  id: '1',
  title: '测试标题',
  content: '测试内容',
  author: global.createMockUser(),
  createdAt: new Date().toISOString(),
  likes: 0,
  comments: [],
})

// Mock localStorage
const localStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
}
global.localStorage = localStorageMock

// Mock sessionStorage
const sessionStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
}
global.sessionStorage = sessionStorageMock

// Mock fetch
global.fetch = vi.fn()

// Mock URL.createObjectURL
global.URL.createObjectURL = vi.fn(() => 'mock-url')
global.URL.revokeObjectURL = vi.fn()

// Mock requestAnimationFrame
global.requestAnimationFrame = vi.fn((cb) => setTimeout(cb, 16))
global.cancelAnimationFrame = vi.fn()

// Mock performance
global.performance = {
  now: vi.fn(() => Date.now()),
  mark: vi.fn(),
  measure: vi.fn(),
  getEntriesByType: vi.fn(() => []),
  getEntriesByName: vi.fn(() => []),
  clearMarks: vi.fn(),
  clearMeasures: vi.fn(),
}